/**
 * 互斥量：C++11中与mutex相关的类(包括锁类型)和函数都声明在头文件<mutex>中
 *  1.C++11提供了4种语义的互斥量
 *      1.std::mutex 独占互斥量，不能递归使用
 *      2.std::time_mutex 带超时的独占互斥量，不能递归使用
 *      3.std::recursive_mutex 递归互斥量，不带超时功能
 *      4.std::recursive_timed_mutex 带超时的递归互斥量
 *    常用的互斥量是std::mutex std::mutex不允许拷贝构造，也不允许move拷贝，最初的mutex对象是处于unlocked状态
 *      1.成员函数 lock()、unlock()、try_lock()
 *         lock:执行线程将锁住该互斥量，线程调用该函数会发生下面3种情况
 *          (1).互斥量处于unlocked状态，则调用线程对该互斥量上锁，直到调用unlock之前，该线程一直拥有该锁
 *          (2).互斥量处于locked状态，被其它线程上锁，则当前线程被阻塞
 *          (3).互斥量处于locked状态，并且被当前线程锁住，则会产生死锁(deadlock)
 *         unlock:解锁，释放对互斥量的所有权
 *         try_lock:执行线程将尝试锁住该互斥量，线程调用该函数会发生下面3种情况
 *          (1).互斥量处于unlocked状态，则调用线程对该互斥量上锁，直到调用unlock之前，该线程一直拥有该锁
 *          (2).互斥量处于locked状态，被其它线程上锁，则当前线程返回false，并不会被阻塞
 *          (3).互斥量处于locked状态，并且被当前线程锁住，则会产生死锁(deadlock)
 *  2.C++11提供了2种管理互斥量的模板类(Mutex RAII)
 *      1.std::lock_guard 构造函数上锁，析构函数解锁，不能手动管理
 *      2.std::unique_lock 相比于std::lock_guard更加灵活，但是效率会低一点
 *    常用的模板类是std::unique_lock std::unique_lock可以进行临时解锁和再上锁
 *      1.构造函数
 *          unique_lock():不管理任何Mutex对象
 *          unique_lock(std::mutex):管理Mutex对象，并尝试调用lock()对Mutex对象进行上锁，如果此时另外某个
 *              unique_lock对象已经管理了该Mutex对象，则当前线程被将会被阻塞
 *          unique_lock(std::mutex,defer_lock_t):管理Mutex对象，但是在初始化的时候并不锁住Mutex对象
 *          unique_lock(std::mutex,try_to_lock_t):管理Mutex对象，并尝试调用try_lock()对Mutex对象进行上锁，
 *              如果上锁不成功，并不会阻塞当前线程
 *          unique_lock(std::mutex,adopt_lock_t):管理Mutex对象，Mutex对象是一个已经被当前线程锁住的Mutex对象
 *      2.成员函数 lock(),try_lock(),try_lock_for(chrono),try_lock_until(chrono),unlock()、release()
 *        owns_lock()
 *          lock:同std::mutex的lock
 *          try_lock:同std::mutex的try_lock
 *          try_lock_for:调用所管理的Mutex对象的try_lock_for函数
 *          try_lock_until:调用所管理的Mutex对象的try_lock_until函数
 *          unlock:同std::mutex的unlock
 *          release:返回所管理的Mutex对象指针，并释放所有权 也就是说这个unique_lock和mutex不再有关系
 *          owns_lock:返回当前std::unique_lock对象是否获得了锁
 *          mutex:返回当前std:unique_lock对象所管理的Mutex对象的指针
 *      3.总结
 *          需要结合notify+wait的场景使用std::unique_lock，单纯的互斥使用std::lock_guard
 *
 * 条件变量：条件变量提供了两类操作：wait和notify，这两类操作构成了多线程同步的基础
 *  1.C++11提供了 std::condition_variable
 *  2.成员函数 notify_one(),notify_all(),wait(std::unique_lock<mutex>),
 *      notify_one:通知wait
 *      notify_all:
 *      wait：先解锁Mutex对象，是的其他锁阻塞的线程可以获得所有权，然后阻塞当前线程的执行，当wait返回时，该线程再次自动
 *          获取Mutex对象
 */

#include "Event.h"

std::mutex &Event::getMutex() {
  return _Mutex;
}

bool Event::lock(UniqueLock &lock) {
  int32_t tID = Get_TID();
  if (_LockID == tID) {
    //如果该互斥量已上锁，同一个线程调用该函数将可能导致死锁情况发生
    if (lock.owns_lock()) {
      return false;
    }
  }

  //如果该互斥量已上锁，则调用线程会阻塞
  lock.lock();

  //将线程ID跟互斥量进行关联
  _LockID = tID;
  return true;
}

void Event::unlock(UniqueLock &lock) {
  if (lock.owns_lock()) {
    lock.unlock();
  }

  _LockID = INVALID_ID;
}


void Event::wait(UniqueLock &lock, TIME_MS timeMs) {
  //wait会先解锁，进入等待状态，之后会再次持有锁(如果多个wait等待就是随机)
  _LockID = INVALID_ID;
  if (timeMs.count() == 0) {
    _Cond.wait(lock);
  } else {
    _Cond.wait_for(lock, timeMs);
  }
  _LockID = Get_TID();
}

void Event::notify(bool notifyAll) {
  if (notifyAll) {
    //可能导致虚假唤醒
    _Cond.notify_all();
  } else {
    _Cond.notify_one();
  }
}